package com.yanqu.road.logic.pb;

import com.yanqu.road.entity.activity.washe.config.WasheConfig;
import com.yanqu.road.entity.activity.washe.config.WasheRankConfig;
import com.yanqu.road.entity.activity.washe.data.WasheUserKey;
import com.yanqu.road.entity.activity.washe.data.WasheUserMatchData;
import com.yanqu.road.entity.activity.washe.eliminate.WasheBlock;
import com.yanqu.road.entity.activity.washe.eliminate.WasheBlockEffect;
import com.yanqu.road.entity.activity.washe.eliminate.WasheBoom;
import com.yanqu.road.entity.activity.washe.eliminate.WasheGameData;
import com.yanqu.road.entity.activity.washe.eliminate.WasheMoveParam;
import com.yanqu.road.entity.activity.washe.eliminate.WasheOperateEffect;
import com.yanqu.road.entity.activity.washe.eliminate.WasheOperateResult;
import com.yanqu.road.entity.activity.washe.eliminate.WasheOperateRoundResult;
import com.yanqu.road.entity.activity.washe.eliminate.WasheOperateShow;
import com.yanqu.road.entity.activity.washe.eliminate.WasheOperateStageResult;
import com.yanqu.road.entity.activity.washe.eliminate.WasheUseSkillParam;
import com.yanqu.road.entity.activity.washe.game.WasheRoomData;
import com.yanqu.road.entity.activity.washe.game.WasheUserGameCard;
import com.yanqu.road.entity.activity.washe.game.WasheUserGameData;
import com.yanqu.road.entity.activity.washe.game.WasheUserGameSkill;
import com.yanqu.road.entity.enums.washe.eWasheBlockEffectType;
import com.yanqu.road.entity.enums.washe.eWasheBoomType;
import com.yanqu.road.pb.activity.WasheProto;

import java.util.List;
import java.util.Map;
import java.util.Objects;

public class WashePb2 {

    public static WasheUserKey parseWasheUserKey(WasheProto.ChannelWasheUserKeyMsg msg) {
        WasheUserKey userKey = new WasheUserKey();
        userKey.setChannelId(msg.getChannelId());
        userKey.setServerId(msg.getServerId());
        userKey.setUserId(msg.getUserId());
        return userKey;
    }

    public static WasheProto.ChannelWasheUserKeyMsg.Builder parseChannelWasheUserKeyMsg(WasheUserKey data) {
        WasheProto.ChannelWasheUserKeyMsg.Builder builder = WasheProto.ChannelWasheUserKeyMsg.newBuilder();
        builder.setChannelId(data.getChannelId());
        builder.setServerId(data.getServerId());
        builder.setUserId(data.getUserId());
        return builder;
    }

    public static WasheProto.WasheOpponentMsg.Builder parseWasheOpponentMsg(WasheUserMatchData data) {
        WasheProto.WasheOpponentMsg.Builder builder = WasheProto.WasheOpponentMsg.newBuilder();
        builder.setScore(data.getScore());
        builder.setUserId(data.isAi() ? 0 : data.getUserId());
        builder.setPlayerInfo(PlayerBasePb.parsePlayerBaseTempMsg(data.getBaseInfo()));
        builder.setChannelId(data.getChannelId());
        builder.setServerName(data.isAi() ? "" : data.getServerName());
        builder.setAreaId(data.getZoneId());
        builder.setAreaWinTimes(data.getWinTimes());
        builder.setAreaWinTimesMax(data.getWinTimesMax());
        return builder;
    }

    public static WasheProto.WasheRoomDataMsg.Builder parseWasheRoomDataMsg(WasheRoomData roomData, String selfKey) {
        boolean isPlayer1 = Objects.equals(roomData.getPlayer1().getUserMatchData().getKey(), selfKey);
        int side = isPlayer1 ? 1 : 2;
        return parseWasheRoomDataMsg(roomData, side);
    }

    public static WasheProto.WasheRoomDataMsg.Builder parseWasheRoomDataMsg(WasheRoomData roomData, int side) {

        WasheUserGameData self = side == 1 ? roomData.getPlayer1() : roomData.getPlayer2();
        WasheUserGameData opponent = side == 1 ? roomData.getPlayer2() : roomData.getPlayer1();

        WasheProto.WasheRoomDataMsg.Builder builder = WasheProto.WasheRoomDataMsg.newBuilder();
        builder.setModeId(roomData.getModeId());
        if (roomData.getGameData() != null) {
            builder.setSceneId(roomData.getGameData().getSceneId());
            builder.setBoard(parseWasheBoardMsg(roomData.getGameData()));
        }
        builder.setOpponent(parseWasheOpponentMsg(opponent.getUserMatchData()));
        builder.setSelfData(parseWasheUserGameDataMsg(side, self));
        builder.setOpponentData(parseWasheUserGameDataMsg(side == 1 ? 2 : 1, opponent));
        builder.setRound(roomData.getRound());
        builder.setExpireTime(roomData.getExpireTime());
        builder.setTurnSide(roomData.getTurnPlayer());
        builder.setShowNo(roomData.getShowNo());
        builder.setRoomId(roomData.getRoomId());
        builder.setIsGuide(roomData.isGuide());
        return builder;
    }

    public static WasheProto.WasheBoardMsg.Builder parseWasheBoardMsg(WasheGameData data) {
        WasheProto.WasheBoardMsg.Builder builder = WasheProto.WasheBoardMsg.newBuilder();
        for (List<WasheBlock> list : data.getBlockList()) {
            for (WasheBlock block : list) {
                builder.addBlockList(parseWasheBlockMsg(block));
            }
        }
        for (Map<Integer, WasheBlock> map : data.getFrameMap().values()) {
            for (WasheBlock frame : map.values()) {
                builder.addBlockList(parseWasheBlockMsg(frame));
            }
        }
        return builder;
    }

    public static WasheProto.WasheUserGameDataMsg.Builder parseWasheUserGameDataMsg(int side, WasheUserGameData data) {
        WasheProto.WasheUserGameDataMsg.Builder builder = WasheProto.WasheUserGameDataMsg.newBuilder();
        builder.setSide(side);
        builder.setScore(data.getScore());
        builder.setStep(data.getStep());

        WasheUserGameCard card = data.getCard();
        builder.setCard(
                WasheProto.WasheUserCardMsg.newBuilder()
                        .setCardId(card.getCardId())
                        .setCardMp(card.getCardMp())
                        .setCardMaxMp(card.getCardMaxMp())
        );

        for (WasheUserGameSkill skill : data.getSkillList()) {
            builder.addSkill(
                    WasheProto.WasheUserSkillMsg.newBuilder()
                            .setSkillId(skill.getSkillId())
                            .setLeftTimes(skill.getTimes())
            );
        }
        builder.setRobot(data.isRobot());
        builder.setRobotScore(data.getRobotScore());
        builder.setUseBoardSkin(data.getBoardSkinId());
        builder.setUseAnimation(data.getAnimationId());
        builder.setUseEffect(data.getEffectId());

        return builder;
    }

    public static WasheProto.WasheBlockMsg.Builder parseWasheBlockMsg(WasheBlock block) {
        WasheProto.WasheBlockMsg.Builder builder = WasheProto.WasheBlockMsg.newBuilder();
        builder.setX(block.getX());
        builder.setY(block.getY());
        builder.setType(block.getBlockType().getValue());
        builder.setColor(block.getColor());
        builder.setDirection(block.getDirection().getValue());
        for (WasheBlockEffect effect : block.getEffectList()) {
            if (effect.getEffectType().getValue() <= eWasheBlockEffectType.SERVER_BEGIN_VALUE) {
                builder.addEffect(parseWasheBlockEffectMsg(effect));
            }
        }
        builder.setScore(block.getScore());
        builder.setSp(block.getSp());
        return builder;
    }

    public static WasheProto.WasheBlockEffectMsg.Builder parseWasheBlockEffectMsg(WasheBlockEffect effect) {
        WasheProto.WasheBlockEffectMsg.Builder builder = WasheProto.WasheBlockEffectMsg.newBuilder();
        builder.setEffectType(effect.getEffectType().getValue());
        builder.setEffectArg(effect.getEffectValue());
        return builder;
    }

    public static WasheProto.WasheGameOverMsg.Builder parseWasheGameOverMsg(WasheRoomData roomData, String selfKey, WasheConfig config) {
        boolean isPlayer1 = Objects.equals(roomData.getPlayer1().getUserMatchData().getKey(), selfKey);
        int side = isPlayer1 ? 1 : 2;
        WasheUserGameData selfGameData = isPlayer1 ? roomData.getPlayer1() : roomData.getPlayer2();
        WasheUserMatchData self = selfGameData.getUserMatchData();
        WasheUserMatchData opponent = (isPlayer1 ? roomData.getPlayer2() : roomData.getPlayer1()).getUserMatchData();

        WasheProto.WasheGameOverMsg.Builder builder = WasheProto.WasheGameOverMsg.newBuilder();
        builder.setRoomData(parseWasheRoomDataMsg(roomData, selfKey));
        builder.setWin(roomData.getWinPlayer() == side);
        builder.setEndType(roomData.getWinType());
        // builder.setScoreChange();
        // builder.setReward();
        // builder.setCostCardId();
        // builder.setMultiBuff();
        // builder.addHonorMomentId();
        builder.setCostTime(System.currentTimeMillis() - roomData.getBeginTime());
        WasheRankConfig washeRankConfig = config.getWasheRankConfig(opponent.getScore(), opponent.isNewHand());
        if (washeRankConfig != null) {
            builder.setLogOpponentRankId(washeRankConfig.getRankId());
        }
        builder.setLogMatchCostTime(self.getMatchCostTime());
        builder.setLogFirstOperate(selfGameData.isFirstOperate());
        int battleResult;
        if (roomData.getWinPlayer() == 3) {
            // 平局
            battleResult = 3;
        } else {
            if (roomData.getWinPlayer() == side) {
                // 胜利
                battleResult = 1;
            } else {
                // 败
                battleResult = 2;
            }
        }
        builder.setBattleResult(battleResult);
        builder.setModeId(roomData.getModeId());
        return builder;
    }

    public static WasheMoveParam parseWasheMoveParam(WasheProto.WasheOperateReqMsg msg) {
        WasheMoveParam param = new WasheMoveParam();
        param.setFromX(msg.getFromX());
        param.setFromY(msg.getFromY());
        param.setToX(msg.getToX());
        param.setToY(msg.getToY());
        return param;
    }

    public static WasheUseSkillParam parseWasheUseSkillParam(WasheProto.WasheOperateReqMsg msg) {
        WasheProto.WasheUseSkillMsg skillMsg = msg.getUseSkill();

        WasheUseSkillParam param = new WasheUseSkillParam();
        param.setSkillId(skillMsg.getId());
        param.setX(skillMsg.getX());
        param.setY(skillMsg.getY());
        param.setToX(skillMsg.getToX());
        param.setToY(skillMsg.getToY());
        return param;
    }

    public static WasheProto.WasheOperateResultMsg.Builder parseWasheOperateResultMsg(WasheOperateResult result,
                                                                                      WasheRoomData roomData,
                                                                                      String receiveUserKey) {
        WasheProto.WasheOperateResultMsg.Builder builder = WasheProto.WasheOperateResultMsg.newBuilder();
        builder.setSide(result.getTurn());
        builder.setSkillId(result.getSkillId());
        for (WasheOperateShow show : result.getShowList()) {
            builder.addShow(parseWasheShowMsg(show));
        }
        builder.setGameData(parseWasheRoomDataMsg(roomData, receiveUserKey));
        return builder;
    }

    public static WasheProto.WasheShowMsg.Builder parseWasheShowMsg(WasheOperateShow show) {
        WasheProto.WasheShowMsg.Builder builder = WasheProto.WasheShowMsg.newBuilder();
        for (WasheOperateEffect effect : show.getEffectList()) {
            builder.addEffects(parseWasheEffectMsg(effect));
        }
        for (WasheOperateRoundResult roundResult : show.getRoundResultList()) {
            builder.addRoundResult(parseWasheRoundResultMsg(roundResult));
        }
        return builder;
    }

    public static WasheProto.WasheEffectMsg.Builder parseWasheEffectMsg(WasheOperateEffect effect) {
        WasheProto.WasheEffectMsg.Builder builder = WasheProto.WasheEffectMsg.newBuilder();
        builder.setEffectType(effect.getEffectType());
        for (WasheBlock block : effect.getBlockList()) {
            builder.addBlockList(parseWasheBlockMsg(block));
        }
        builder.setParam(effect.getParam());
        return builder;
    }

    public static WasheProto.WasheRoundResultMsg.Builder parseWasheRoundResultMsg(WasheOperateRoundResult roundResult) {
        WasheProto.WasheRoundResultMsg.Builder builder = WasheProto.WasheRoundResultMsg.newBuilder();
        builder.setType(roundResult.isRearrange() ? 2 : 1);
        for (WasheOperateStageResult stageResult : roundResult.getStageResultList()) {
            builder.addStageResult(parseWasheStageResultMsg(stageResult));
        }
        for (WasheBlock bomb : roundResult.getNewBombList()) {
            builder.addCreateBomb(parseWasheBlockMsg(bomb));
        }
        builder.setBoard(parseWasheBoardMsg(roundResult.getGameData()));
        return builder;
    }

    public static WasheProto.WasheStageResultMsg.Builder parseWasheStageResultMsg(WasheOperateStageResult stageResult) {
        WasheProto.WasheStageResultMsg.Builder builder = WasheProto.WasheStageResultMsg.newBuilder();
        for (WasheBlock block : stageResult.getEliminateList()) {
            builder.addBlockList(parseWasheBlockMsg(block));
        }
        for (WasheBoom boom : stageResult.getBoomList()) {
            if (boom.getBoomType() != eWasheBoomType.Empty) {
                builder.addBoomList(parseWasheBoomMsg(boom));
            }
        }
        for (WasheBlock block : stageResult.getAddStepBlockList()) {
            builder.addBlockList2(parseWasheBlockMsg(block));
        }
        return builder;
    }

    public static WasheProto.WasheBoomMsg.Builder parseWasheBoomMsg(WasheBoom boom) {
        WasheProto.WasheBoomMsg.Builder builder = WasheProto.WasheBoomMsg.newBuilder();
        builder.setX(boom.getX());
        builder.setY(boom.getY());
        builder.setType(boom.getBoomType().getValue());
        for (WasheBlock block : boom.getBlockList()) {
            builder.addBlockList(parseWasheBlockMsg(block));
        }
        return builder;
    }

    public static WasheProto.WasheFriendRoomInfoMsg.Builder parseWasheFriendRoomInfoMsg(WasheRoomData roomData, boolean isPlayer1) {
        WasheUserGameData player1 = roomData.getPlayer1();
        WasheUserGameData player2 = roomData.getPlayer2();
        WasheUserGameData opponent = isPlayer1 ? player2 : player1;

        WasheProto.WasheFriendRoomInfoMsg.Builder builder = WasheProto.WasheFriendRoomInfoMsg.newBuilder();
        builder.setRoomId(String.valueOf(roomData.getRoomId()));
        if (opponent != null) {
            builder.setFriend(parseWasheOpponentMsg(opponent.getUserMatchData()));
        }
        builder.setSceneId(roomData.getGameData() != null ? roomData.getGameData().getSceneId() : roomData.getAppointSceneId());
        builder.setStepOut(player1.getStepOutTime() > 0);

        builder.setMasterUserId(player1.getUserMatchData().getUserId());
        builder.setCardId1(player1.getUserMatchData().getCardId());
        if (player2 != null) {
            builder.setCardId2(player2.getUserMatchData().getCardId());
            builder.setReady(player2.isReady());
        } else {
            builder.setReady(false);
        }

        builder.addAllSkillId1(player1.getUserMatchData().getSkills());
        if (player2 != null) {
            builder.addAllSkillId2(player2.getUserMatchData().getSkills());
        }

        return builder;
    }
}
